package ycl.scheduled.common.utils;

import ycl.scheduled.common.enums.AddressEnum;
import ycl.scheduled.common.models.tencent.maps.Location;
import ycl.scheduled.common.models.tencent.maps.req.BaseGpsQueryReq;

import java.math.BigDecimal;

/**
 * 定位工具
 *
 * @author: YCL
 * @date: 2021-09-24 12:23:24
 */
public class GpsUtil {

	private static final int EARTH_RADIUS = 6378137;//地球半径
	private static final BigDecimal MIN_LNG = new BigDecimal("-180");//最小经度
	private static final BigDecimal MAX_LNG = new BigDecimal("180");//最大经度
	private static final BigDecimal MIN_LAT = new BigDecimal("-90");//最小纬度
	private static final BigDecimal MAX_LAT = new BigDecimal("90");//最大纬度
	private static final BigDecimal ZERO = BigDecimal.ZERO;//0

	private static final BigDecimal NORTH = new BigDecimal("53.560000");//中国大陆最北
	private static final BigDecimal SOUTH = new BigDecimal("3.764000");//中国大陆最南
	private static final BigDecimal EAST = new BigDecimal("135.078600");//中国大陆最东
	private static final BigDecimal WEST = new BigDecimal("73.516100");//中国大陆最西


	/**
	 * 中国地址合法性校验
	 *
	 * @param location 坐标
	 * @return 是否在中国境内
	 */
	public static boolean locationLegalVerify(Location location) {
		return locationLegalVerify(location.getLat(), location.getLng());
	}


	/**
	 * 中国地址合法校验
	 *
	 * @param lat 纬度
	 * @param lng 经度
	 * @return 是否在中国境内
	 */
	public static boolean locationLegalVerify(BigDecimal lat, BigDecimal lng) {
		return (lat == null || lng == null
				|| lat.compareTo(NORTH) > 0 || lat.compareTo(SOUTH) < 0
				|| lng.compareTo(EAST) > 0 || lng.compareTo(WEST) < 0);
	}

	/**
	 * 获取定位, 如果定位失败返回默认地址
	 *
	 * @param location 位置
	 * @return 要是在中国境内就是当前位置, 否则就是默认地址
	 */
	public static Location getLocation(Location location) {
		return getLocation(location.getLat(), location.getLng(), location.getDistance());
	}

	public static <T extends BaseGpsQueryReq> Location getLocation(T t) {
		return getLocation(t.getLat(), t.getLng(), t.getDistance());
	}


	/**
	 * 不是在中国大陆境内自动返回默认地址
	 *
	 * @param lat      纬度
	 * @param lng      经度
	 * @param distance 距离
	 * @return 新的地址对象
	 */
	public static Location getLocation(BigDecimal lat, BigDecimal lng, BigDecimal distance) {
		if (! locationLegalVerify(lat, lng)) {
			AddressEnum def = AddressEnum.getDefault();
			lat = def.getLat();
			lng = def.getLng();
		}
		if (distance.compareTo(ZERO) <= 0)
			distance = new BigDecimal("1000");
		return new Location(lat, lng, distance);
	}


	/**
	 * 获取两个位置的距离
	 *
	 * @param l1 位置1
	 * @param l2 位置2
	 * @return 两个位置的距离(m)
	 */
	public static int getDistance(Location l1, Location l2) {
		return getDistance(l1.getLat(), l1.getLng(), l2.getLat(), l2.getLng());
	}

	/**
	 * 获取两个位置的距离(m)
	 *
	 * @param lat1 位置1纬度
	 * @param lng1 位置1经度
	 * @param lat2 位置2纬度
	 * @param lng2 位置2经度
	 * @return 距离
	 */
	public static int getDistance(BigDecimal lat1, BigDecimal lng1, BigDecimal lat2, BigDecimal lng2) {
		double rt1 = getRad(lat1);
		double rg1 = getRad(lng1);
		double rt2 = getRad(lat2);
		double rg2 = getRad(lng2);

		double x = rg1 - rg2;//经度弧长
		double y = rt1 - rt2;//纬度弧长

		double s = 2 * Math.asin(
				Math.sqrt(Math.pow(Math.sin(y / 2), 2))
						+ Math.cos(rt1) * Math.cos(rt2) * Math.pow(Math.sin(x / 2), 2));
		return (int) (s * EARTH_RADIUS);
	}


	/**
	 * 获取从地心到此位置的弧长
	 *
	 * @param x 经度或纬度的一条线
	 * @return 弧长
	 */
	private static double getRad(BigDecimal x) {
		double n = Double.parseDouble(x.toString());
		return n * Math.PI / 180;
	}
}
